#!/usr/bin/env python
# encoding: utf-8

from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *

import platform
from threading import Thread

import serial
import serial.tools.list_ports

from common.libs.Log import logging
import time

from common.libs.ComDeal import WATER_CMD,ComDeal
from common.libs.MathFunc import MathFunc
from common.libs.Helper import Helper

import queue
import os
import configparser
import threading
import binascii
import re
import random

from dlg.ComSetDialog import ComSetDialog 
from dlg.MeasurePictureDialog import MeasurePictureDialog 
from dlg.EnvMeasureDialog import EnvMeasureDialog
from dlg.FlowMeasureDialog import FlowMeasureDialog 
from dlg.baseSet import BaseSet
from dlg.projectManager import ProjectTreeWidget

import PyQt5_stylesheets

from ui.app import Ui_MainWindow
# 图片资源文件导入
from ui import images

# import pysnooper

# filename = '%s/log/%s_debug.log'%(os.getcwd(), time.strftime("%Y%m%d", time.localtime()))
# version = 'v1.0.1'

class main(QMainWindow, Ui_MainWindow):

    # 串口接收定时器开启信号
    signal_serial_timer = pyqtSignal()

    task_move_first = False

    def __init__(self, parent=None):
        super(main, self).__init__()
        self.setupUi(self)

        # self.setWindowFlags(Qt.FramelessWindowHint)

        # 设置字体
        self.font = QFont()
        self.font.setFamily("Agency FB")
        self.font.setPointSize(32)
        self.setFont(self.font)

        self.setWindowTitle('洗胃机检测仪器')
        self.setWindowIcon(QIcon(':icons/img/app.ico'))

        # 项目管理界面
        # self.proj_tree = ProjectTreeWidget(save_path=os.getcwd()+'\\projects')
        # self.verticalLayout.addWidget(self.proj_tree)

        # 测量示意图
        self.measurePictureDialog = MeasurePictureDialog()
        self.pushButton_measure_picture.clicked.connect(self.measurePictureDialog.show)
        # 串口界面
        self.comSetDialog = ComSetDialog()
        self.comSetDialog.setFont(self.font)
        self.pushButton_com.clicked.connect(self.comSetDialog.exec)
        self.pushButton_com.setIcon(QIcon(':icons/img/com-offline.png'))

        # 本底测量
        self.envMeasureDialog = EnvMeasureDialog()
        self.envMeasureDialog.signal_send.connect(self.SerialWrite)
        self.envMeasureDialog.setFont(self.font)
        self.pushButton_env.clicked.connect(self.envMeasureDialog.exec)
        self.pushButton_env.setIcon(QIcon(':icons/img/box.png'))

        # 基本设置界面
        self.baseSetWidget = BaseSet()
        self.baseSetWidget.setFont(self.font)
        self.baseSetWidget.signal_send.connect(self.SerialWrite)
        self.pushButton_set.clicked.connect(self.baseSetWidget.show)

        # 流量检测界面
        self.flowMeasureDialog = FlowMeasureDialog()
        self.flowMeasureDialog.signal_send.connect(self.SerialWrite)
        self.flowMeasureDialog.setFont(self.font)
        self.pushButton_flow.clicked.connect(self.flowMeasureDialog.show)

        self.signal_serial_timer.connect(self.serialRecvTimer)

        self.serial = serial.Serial()
        self.serialInit()

        # 固定窗口大小与屏幕大小相同
        self.fixedSize()

    def fixedSize(self):
        self.desktop = QApplication.desktop()
 
        #获取显示器分辨率大小
        self.screenRect = self.desktop.screenGeometry()
        width = self.screenRect.width()
        height = self.screenRect.height() - 50
        self.setFixedSize(width, height)
        self.comSetDialog.setFixedSize(width,height)
        self.envMeasureDialog.setFixedSize(width,height)
        self.baseSetWidget.setFixedSize(width,height)
        self.flowMeasureDialog.setFixedSize(width,height)
        self.measurePictureDialog.setFixedSize(width,height)
 

    # def createMenus(self):
    #     self.comSetAct = QAction("&通信", self, triggered=self.comSetDialog.show)
    #     self.label_comStatus= QLabel()
    #     self.label_comStatus.setMinimumWidth(32)
    #     self.label_comStatus.setStyleSheet('image: url(:icons/img/com-offline.png)')
    #     self.readInfoAct = QAction(QIcon(':icons/img/info.png'),'&读信息', self, triggered=self.cmdReadInfo)
    #     self.envAct = QAction(QIcon(':icons/img/box.png'),'&本底', self, triggered=self.envMeasureDialog.exec)

    #     # self.newProjectAct = QAction(QIcon(':icons/img/project.png'),"&新建", self, shortcut="Ctrl+N", triggered=self.proj_tree.newProject)
    #     # self.openProjectAct = QAction(QIcon(':icons/img/open.png'), "&打开", self, shortcut="Ctrl+O", triggered=self.proj_tree.openProject)
    #     # self.closeProjectAct = QAction(QIcon(':icons/img/close.png'), "&关闭", self, shortcut="Ctrl+C", triggered=self.proj_tree.closeProject)
    #     # self.exitAct = QAction(QIcon(':icons/img/close.png'), "&退出", self, shortcut="Ctrl+Q", statusTip="关闭程序", triggered=self.close)

    #     self.baseSetAct = QAction(QIcon(':icons/img/info.png'),'&基本参数设置', self, triggered=self.baseSetShow)
    #     # 字体大小设置
    #     self.font_16_Act = QAction('&大', self, triggered=lambda:self.fontSizeChanged(16))
    #     self.font_12_Act = QAction('&中', self, triggered=lambda:self.fontSizeChanged(13))
    #     self.font_10_Act = QAction('&小', self, triggered=lambda:self.fontSizeChanged(10))
    #     # 皮肤设置
    #     self.skinDefaultAct = QAction('&经典(默认)', self, triggered=lambda:self.skinChanged('default'))
    #     self.skinBlackAct = QAction('&黑色', self, triggered=lambda:self.skinChanged('dark'))
    #     self.skinBlueAct = QAction('&天蓝色', self, triggered=lambda:self.skinChanged('blue'))
    #     self.versionAct = QAction('&版本信息', self, triggered=self.showVersion)

    def fontSizeChanged(self, size=12):
        font = self.font()
        font.setPointSize(size)
        self.setFont(font)

    def skinChanged(self, name='default'):
        if name == "default":
            self.setStyleSheet('None')
            self.comSetDialog.setStyleSheet('None')
            self.proj_tree.createProjectDlg.setStyleSheet('None')
            self.baseSetWidget.setStyleSheet('None')
        if name == "dark":
            self.setStyleSheet(PyQt5_stylesheets.load_stylesheet_pyqt5(style="style_Dark"))
            self.comSetDialog.setStyleSheet(PyQt5_stylesheets.load_stylesheet_pyqt5(style="style_Dark"))
            self.proj_tree.createProjectDlg.setStyleSheet(PyQt5_stylesheets.load_stylesheet_pyqt5(style="style_Dark"))
            self.baseSetWidget.setStyleSheet(PyQt5_stylesheets.load_stylesheet_pyqt5(style="style_Dark"))
        if name == "blue":
            self.setStyleSheet(PyQt5_stylesheets.load_stylesheet_pyqt5(style="style_blue"))
            self.comSetDialog.setStyleSheet(PyQt5_stylesheets.load_stylesheet_pyqt5(style="style_blue"))
            self.proj_tree.createProjectDlg.setStyleSheet(PyQt5_stylesheets.load_stylesheet_pyqt5(style="style_blue"))
            self.baseSetWidget.setStyleSheet(PyQt5_stylesheets.load_stylesheet_pyqt5(style="style_blue"))

    def showVersion(self):
        QMessageBox.information(self, '版本信息','当前软件版本: %s'%version,QMessageBox.Yes)

    def serialInit(self):
        '''初始化串口'''
        self.serial.timeout = 0.5  # make sure that the alive event can be checked from time to time
        self.thread = None
        self.serial_alive = False
        self.serial.port = None
        self.serial.baudrate = '115200'
        self.serial.bytesize = 8
        self.serial.parity = 'N'
        self.serial.stopbits = 1
        self.serial.dtr = True
        self.serial.rts = True
        self.recv = ''
        self.startFindOpenSerial()

    def baseSetShow(self):
        self.baseSetWidget.exec()
        # text, okPressed = QInputDialog.getText(self, "请输入密码","密码:", QLineEdit.Normal, "")
        # if okPressed:
            # if text == 'fushe01020304':
            # else:
            #     QMessageBox.information(self, '提示', '密码错误', QMessageBox.Yes)

    def startFindOpenSerial(self):
        # 串口查询定时器
        self.thread_find_open = threading.Thread(target=self.serialFindOpen)
        self.thread_find_open.setDaemon(True)
        self.thread_find_open.start()

    def serialFindOpen(self):
        '''搜索串口并打开串口'''
        while not self.serial_alive:
            config = configparser.ConfigParser()
            if platform.system() == "Windows":
                config.read(os.getcwd() + '/conf/com.ini')
            if platform.system() == "Linux":
                config.read('/home/pi/conf/com.ini')
            port = config['com']['device']
            baudrate = config['com']['baudrate']
            if port and baudrate:
                self.serial.port = port
                # self.serial.baudrate = '460800'
                self.serial.baudrate = baudrate
                try:
                    self.serial.open()
                    logging.info('打开串口: %s-%s'%(self.serial.port, self.serial.baudrate))
                except serial.SerialException as e:
                    pass
                else:
                    self.serial_alive = True
                    self.signal_serial_timer.emit()
            else:
                pass

    def SerialWrite(self, cmd):
        '''串口写入,十六进制格式字符串'''
        if self.serial_alive:
            if self.serial.isOpen():
                data = binascii.unhexlify(cmd)
                self.serial.write(data)
                logging.info('发送命令：'+' '.join([cmd[i * 2:i * 2 + 2] for i in range(0, int(len(cmd) / 2))]))
        else:
            QMessageBox.information(self, '通信提示', '通信异常,请检查通信接口', QMessageBox.Yes)

    def serialRecvTimer(self):
        """串口接收定时器"""
        self.timer_recv = QTimer()
        self.timer_recv.timeout.connect(self.serialRecv)
        self.timer_recv.start(200)
        # self.label_comStatus.setStyleSheet('image: url(:icons/img/com.png)')
        self.pushButton_com.setIcon(QIcon(':icons/img/com.png'))
        # self.cmdReadInfo()

    def serialRecv(self):
        """串口接收"""
        if self.serial_alive:
            try:
                n = self.serial.inWaiting()
                if n:
                    b = self.serial.read(n)
                    # 将byte转换为十六进制字符串
                    data = str(binascii.b2a_hex(b).decode('utf-8'))
                    self.recv += data.upper()
                    logging.info('接收命令：'+' '.join([self.recv[i * 2:i * 2 + 2] for i in range(0, int(len(self.recv) / 2))]))
                    try:
                        self.serialCmdDeal()
                    except Exception as e:
                        logging.info(e)
            except:
                logging.warn("串口异常")
                # self.label_comStatus.setStyleSheet('image: url(:icons/img/com-offline.png)')
                self.pushButton_com.setIcon(QIcon(':icons/img/com-offline.png'))
                # 串口异常, 关闭串口
                if self.serial.isOpen():
                    self.serial_alive = False
                    self.serial.close()
                    # 打开串口查询线程
                    self.startFindOpenSerial()

    def serialCmdDeal(self):
        '''串口处理命令，监测校验和是否正确'''
        self.recv = self.recv
        start = self.recv.find("AA")
        startwith = self.recv.startswith('AA')
        def find_last(string, s):
            last_position = -1
            while True:
                position = string.find(s, last_position + 1)
                if position == -1:
                    return last_position
                last_position = position
        start_num = len(re.compile('.*?(AA).*?').findall(self.recv))
        if self.recv.startswith('AA'):
            for i in re.compile('.*?(AA).*?').findall(self.recv):
                # if len(self.recv)>6:
                theory_len = int(self.recv[2:4], 16)
                real_len = len(self.recv) / 2
                if theory_len <= real_len:
                    cmd = self.recv[start:theory_len * 2]
                    self.recv = self.recv[theory_len * 2:]
                    # print('截取后',self.recv)
                    cmd_start = cmd[0:2]
                    cmd_len = cmd[2:4]
                    cmd_sum = cmd[4:6]
                    if cmd_sum == (hex(int(cmd_start, 16) + int(cmd_len, 16))).upper()[-2:]:
                        cmd_cmd = cmd[6:8]
                        cmd_data = cmd[8:-2]
                        cmd_endsum = cmd[-2:]
                        s = 0
                        for i in range(0, len(cmd) - 2):
                            if i % 2 == 0:
                                s = s + int(cmd[i:i + 2], 16)
                        s = hex(s).upper()[-2:]
                        if s == cmd_endsum:
                            try:
                                self.serialCmdType(cmd_cmd, cmd_data)
                            except Exception as e:
                                logging.error(e)
                        else:
                            self.recv = ''
                            logging.error('校验错误！')
                            logging.error('正确校验码:%s, 错误：%s'%(s,cmd_endsum))
                else:
                    return
        else:
            self.recv = self.recv[self.recv.find('AA'):]

    # @pysnooper.snoop(filename)
    def serialCmdType(self, cmd, data):
        logging.info("收到命令：%s 数据：%s"%(cmd,data))
        if cmd == 'EE':
            if data=="01":
                QMessageBox.information(self,'提示','走步运行中，请等待运行完成!',QMessageBox.Yes)
            if data=="02":
                QMessageBox.information(self,'提示','测量运行中，请等待运行完成!',QMessageBox.Yes)
            if data=="03":
                QMessageBox.information(self,'提示','本底测量运行中，请等待运行完成!',QMessageBox.Yes)
            if data=="04":
                QMessageBox.information(self,'提示','累积剂量测量运行中，请等待运行完成!',QMessageBox.Yes)
        if cmd == '72':  # 本底测量
            logging.info('接收到本底测量相关命令~~')
            self.envMeasureDialog.serialDeal(data)
            return
        if cmd == '71' or cmd == '73':
            if self.flowMeasureDialog.measure_flag:
                logging.info('处理流量接收数据~~')
                self.flowMeasureDialog.serialDeal(cmd, data)
            return
        if cmd == '42' or cmd == '43':
            logging.info('接收到读写flash相关命令~~')
            self.baseSetWidget.serialDeal(cmd, data)
            return
        if cmd == '82':
            _len = int(data[0:2], 16)
            # flash信息处理
            flash_start = 2
            flash_end = 2+_len*2
            flash_info = data[flash_start:flash_end]
            self.baseSetWidget.setParameter(flash_info)
            # 设置脉冲数
            self.motorMove.pulse_x  = self.baseSetWidget.pulse
            self.motorMove.pulse_y  = self.baseSetWidget.pulse
            self.motorMove.pulse_z  = self.baseSetWidget.pulse
            # 坐标信息处理
            axis_start = flash_end
            axis_end = flash_end + 3*4*2
            axis_info = data[axis_start:axis_end]
            x = MathFunc.hexStrToInt(axis_info[0:8])
            y = MathFunc.hexStrToInt(axis_info[8:16])
            z = MathFunc.hexStrToInt(axis_info[16:24])
            x,y,z = self.motorMove.setAxis(x,y,z)
            self.label_axix_x.setText('%3.3f'%x)
            # 设置测量系数
            self.leakageRayDlg.scale_k = self.baseSetWidget.scale_k_leakage
            self.leakageRayDlg.scale_b = self.baseSetWidget.scale_b_leakage

            # 重复性测量系数
            self.repeatMeasureWidget.scale_k_1 = self.baseSetWidget.scale_k
            self.repeatMeasureWidget.scale_b_1 = self.baseSetWidget.scale_b
            self.repeatMeasureWidget.scale_k_2 = self.baseSetWidget.scale_k_2
            self.repeatMeasureWidget.scale_b_3 = self.baseSetWidget.scale_b_2

            # 空气比释动能系数
            self.airKermaDlg.scale_k_1 = self.baseSetWidget.scale_k
            self.airKermaDlg.scale_b_1 = self.baseSetWidget.scale_b
            self.airKermaDlg.scale_k_2 = self.baseSetWidget.scale_k_2
            self.airKermaDlg.scale_b_2 = self.baseSetWidget.scale_b_2

            # 辐射角刻度系数
            self.radioAngleDlg.scale_k_1 = self.baseSetWidget.scale_k
            self.radioAngleDlg.scale_b_1 = self.baseSetWidget.scale_b
            self.radioAngleDlg.scale_k_2 = self.baseSetWidget.scale_k_2
            self.radioAngleDlg.scale_b_2 = self.baseSetWidget.scale_b_2

            self.airKermaDlg.airKermaPowerTable = self.baseSetWidget.airKermaPowerTable
            self.leakageRayDlg.leakageRayPowerTable= self.baseSetWidget.leakageRayPowerTable

            QMessageBox.information(self, '提示','读取下位机成功',QMessageBox.Yes)

    def cmdRunTask(self, task):
        '''发送执行任务命令'''
        road = task['road']
        logging.info("发送坐标:")
        logging.info(road)
        data_len = MathFunc.intToHexStr(len(road), 4)
        data_axis = ''
        for a in road:
            x,y,z = self.motorMove.axisToPulse(a[0],a[1],a[2])
            data_x = MathFunc.intToHexStr(x, 4)
            data_y = MathFunc.intToHexStr(y, 4)
            data_z = MathFunc.intToHexStr(z, 4)
            data_axis +=data_x + data_y + data_z
        cmd = WATER_CMD['任务坐标']
        cmd[4] = data_len + data_axis
        new_cmd = ComDeal.getCmd(cmd)
        self.SerialWrite(new_cmd)

    def cmdReadInfo(self):
        cmd = WATER_CMD['读取信息']
        # read_length = '60'
        # cmd[4] = hex(read_length).replace('0x','').zfill(2)
        cmd[4] = '64'
        new_cmd = ComDeal.getCmd(cmd)
        self.SerialWrite(new_cmd)

    def taskRunInit(self):
        self.task_cmd_queue = queue.Queue()

        self.task = None
        self.task_cnt = 0
        self.task_current = None
        self.task_run_flag = False

        #  self.task_cmd_thread = Thread(target=taskCmdThread, args=(self.task_cmd_queue ,))
        #  self.task_cmd_thread.setDaemon(True)
        #  self.task_cmd_thread.start()

        self.task_run_thread = Thread(target=self.taskRunThread, args=(self.task_cmd_queue ,))
        self.task_run_thread.setDaemon(True)
        self.task_run_thread_done = False
        self.task_run_thread.start()

    def taskStart(self, task):
        self.task = task
        logging.info("执行任务：")
        logging.info(task)
        self.task_cmd_queue.put('first')
        self.task_run_flag = True

    def taskContinue(self):
        self.task_cmd_queue.put("continue")

    def taskRunThread(self, in_q):
        """消费者"""
        while True:
            cmd = in_q.get()
            logging.info("收到指令："+cmd)
            if cmd == "first": # 移动到第一个点
                pos = self.task['road'][0]
                self.motorMove.movePos(pos[0], pos[1], pos[2])
            if cmd == "continue": # 移动到第一个点
                road = self.task['road']
                self.motorMove.measureMove(road)
            if cmd == "pause": # 移动到第一个点
                self.motorMove.measureMoveStop()



if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)
    form = main()
    form.show()
    app.exec_()
